package com.detector.overflow.config;

import java.io.*;
import java.util.HashSet;
import java.util.Set;

/**
 * 检测器配置类
 * 通过系统属性进行配置
 *
 * @author detector
 */
public class DetectorConfig {
    
    // 默认配置
    private static final double DEFAULT_THRESHOLD = 0.7;
    private static final String DEFAULT_LOG_FILE = "overflow-monitor.log";
    private static final int DEFAULT_MAX_WARNINGS = 1;
    
    // 配置项
    private final double threshold;
    private final String logFile;
    private final String[] monitorPackages;
    private final String[] excludePackages;
    private final int maxWarnings;
    private final Set<String> whitelistMethods;  // 白名单方法集合
    
    private static DetectorConfig instance;
    
    private DetectorConfig() {
        // 从系统属性读取配置
        this.threshold = Double.parseDouble(
            System.getProperty("overflow.threshold", String.valueOf(DEFAULT_THRESHOLD))
        );
        
        this.logFile = System.getProperty("overflow.logfile", DEFAULT_LOG_FILE);
        
        this.maxWarnings = Integer.parseInt(
            System.getProperty("overflow.maxWarnings", String.valueOf(DEFAULT_MAX_WARNINGS))
        );
        
        // 监控的包名（逗号分隔）
        String packages = System.getProperty("overflow.packages", "");
        this.monitorPackages = packages.isEmpty() ? new String[0] : packages.split(",");
        
        // 排除的包名（默认排除JDK核心包）
        String exclude = System.getProperty("overflow.excludePackages", 
            "java.,javax.,sun.,com.sun.,jdk.,org.springframework.cglib");
        this.excludePackages = exclude.split(",");
        
        // 加载白名单配置
        this.whitelistMethods = loadWhitelist();
    }
    
    public static DetectorConfig getInstance() {
        if (instance == null) {
            synchronized (DetectorConfig.class) {
                if (instance == null) {
                    instance = new DetectorConfig();
                }
            }
        }
        return instance;
    }
    
    /**
     * 判断是否应该监控该类
     */
    public boolean shouldMonitor(String className) {
        if (className == null) {
            return false;
        }
        
        // 替换 / 为 .
        String dotClassName = className.replace('/', '.');
        
        // 检查排除列表
        for (String exclude : excludePackages) {
            if (dotClassName.startsWith(exclude.trim())) {
                return false;
            }
        }
        
        // 如果指定了监控包，则只监控这些包
        if (monitorPackages.length > 0) {
            for (String pkg : monitorPackages) {
                if (dotClassName.startsWith(pkg.trim())) {
                    return true;
                }
            }
            return false;
        }
        
        // 默认监控所有（除了排除列表）
        return true;
    }
    
    /**
     * 加载白名单配置文件
     */
    private Set<String> loadWhitelist() {
        Set<String> whitelist = new HashSet<>();
        
        // 从系统属性获取配置文件路径
        String whitelistFile = System.getProperty("overflow.whitelist", "overflow-whitelist.txt");
        
        File file = new File(whitelistFile);
        if (!file.exists()) {
            // 如果文件不存在，返回空集合
            return whitelist;
        }
        
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                // 跳过空行和注释
                if (line.isEmpty() || line.startsWith("#")) {
                    continue;
                }
                whitelist.add(line);
            }
            System.out.println("✅ 加载白名单配置: " + whitelistFile + " (" + whitelist.size() + " 个方法)");
        } catch (IOException e) {
            System.err.println("⚠️  无法读取白名单文件: " + whitelistFile + " - " + e.getMessage());
        }
        
        return whitelist;
    }
    
    /**
     * 判断方法是否在白名单中（跳过检查）
     * 
     * @param className 类名，格式: com.example.MyClass
     * @param methodName 方法名
     * @param methodDescriptor 方法描述符，格式: (II)V 或 (Ljava/lang/String;)I
     * @return true 表示在白名单中，应该跳过
     */
    public boolean isWhitelisted(String className, String methodName, String methodDescriptor) {
        if (whitelistMethods.isEmpty()) {
            return false;
        }
        
        String fullMethodName = className + "." + methodName;
        String fullMethodSignature = className + "." + methodName + convertDescriptorToReadable(methodDescriptor);
        
        // 精确匹配：带参数签名
        if (whitelistMethods.contains(fullMethodSignature)) {
            return true;
        }
        
        // 精确匹配：不带参数（匹配所有重载）
        if (whitelistMethods.contains(fullMethodName)) {
            return true;
        }
        
        // 支持通配符匹配
        for (String pattern : whitelistMethods) {
            if (pattern.endsWith("*")) {
                // 匹配前缀，例如: com.example.MyClass.*
                String prefix = pattern.substring(0, pattern.length() - 1);
                if (fullMethodSignature.startsWith(prefix) || fullMethodName.startsWith(prefix)) {
                    return true;
                }
            } else if (pattern.contains("*")) {
                // 支持中间通配符，例如: com.example.*.calculate
                String regex = pattern.replace(".", "\\.").replace("*", ".*");
                if (fullMethodSignature.matches(regex) || fullMethodName.matches(regex)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * 将字节码方法描述符转换为可读的参数列表格式
     * 例如: (II)V -> (int,int)
     *      (Ljava/lang/String;I)V -> (String,int)
     *      ()V -> ()
     */
    private String convertDescriptorToReadable(String descriptor) {
        if (descriptor == null || !descriptor.startsWith("(")) {
            return "";
        }
        
        int endIndex = descriptor.indexOf(')');
        if (endIndex == -1) {
            return "";
        }
        
        String params = descriptor.substring(1, endIndex);
        if (params.isEmpty()) {
            return "()";
        }
        
        StringBuilder readable = new StringBuilder("(");
        int i = 0;
        boolean first = true;
        
        while (i < params.length()) {
            if (!first) {
                readable.append(",");
            }
            first = false;
            
            char c = params.charAt(i);
            switch (c) {
                case 'Z':
                    readable.append("boolean");
                    i++;
                    break;
                case 'B':
                    readable.append("byte");
                    i++;
                    break;
                case 'C':
                    readable.append("char");
                    i++;
                    break;
                case 'S':
                    readable.append("short");
                    i++;
                    break;
                case 'I':
                    readable.append("int");
                    i++;
                    break;
                case 'J':
                    readable.append("long");
                    i++;
                    break;
                case 'F':
                    readable.append("float");
                    i++;
                    break;
                case 'D':
                    readable.append("double");
                    i++;
                    break;
                case 'L':
                    // 对象类型，格式: Ljava/lang/String;
                    int semicolon = params.indexOf(';', i);
                    if (semicolon != -1) {
                        String className = params.substring(i + 1, semicolon);
                        // 只取类名，不包括包名
                        int lastSlash = className.lastIndexOf('/');
                        if (lastSlash != -1) {
                            className = className.substring(lastSlash + 1);
                        }
                        readable.append(className);
                        i = semicolon + 1;
                    } else {
                        i++;
                    }
                    break;
                case '[':
                    // 数组类型
                    int arrayDim = 0;
                    while (i < params.length() && params.charAt(i) == '[') {
                        arrayDim++;
                        i++;
                    }
                    // 递归处理数组元素类型（简化处理）
                    if (i < params.length()) {
                        char elemType = params.charAt(i);
                        if (elemType == 'L') {
                            int semicolon2 = params.indexOf(';', i);
                            if (semicolon2 != -1) {
                                String className2 = params.substring(i + 1, semicolon2);
                                int lastSlash2 = className2.lastIndexOf('/');
                                if (lastSlash2 != -1) {
                                    className2 = className2.substring(lastSlash2 + 1);
                                }
                                readable.append(className2);
                                i = semicolon2 + 1;
                            }
                        } else {
                            // 基本类型数组
                            String typeName = "";
                            switch (elemType) {
                                case 'I': typeName = "int"; break;
                                case 'J': typeName = "long"; break;
                                case 'F': typeName = "float"; break;
                                case 'D': typeName = "double"; break;
                                case 'Z': typeName = "boolean"; break;
                                case 'B': typeName = "byte"; break;
                                case 'C': typeName = "char"; break;
                                case 'S': typeName = "short"; break;
                            }
                            readable.append(typeName);
                            i++;
                        }
                    }
                    for (int j = 0; j < arrayDim; j++) {
                        readable.append("[]");
                    }
                    break;
                default:
                    i++;
                    break;
            }
        }
        
        readable.append(")");
        return readable.toString();
    }
    
    public double getThreshold() {
        return threshold;
    }
    
    public String getLogFile() {
        return logFile;
    }
    
    public int getMaxWarnings() {
        return maxWarnings;
    }
    
    public void printConfig() {
        System.out.println("=== 溢出检测器配置 ===");
        System.out.println("警告阈值: " + (int)(threshold * 100) + "%");
        System.out.println("日志文件: " + logFile);
        System.out.println("最大警告次数: " + maxWarnings);
        
        if (monitorPackages.length > 0) {
            System.out.println("监控包: " + String.join(", ", monitorPackages));
        } else {
            System.out.println("监控包: 所有包");
        }
        
        System.out.println("排除包: " + String.join(", ", excludePackages));
        
        if (!whitelistMethods.isEmpty()) {
            System.out.println("白名单方法数: " + whitelistMethods.size());
        }
        
        System.out.println("======================\n");
    }
}
